package com.earth.c.plugins.shiro;


import java.util.ArrayList;
import java.util.Collection;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.SessionListener;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator;
import org.apache.shiro.session.mgt.eis.SessionIdGenerator;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


@Configuration
public class ShiroConfig {

	@Value("${shiro.login.url}")
	private String loginUrl;

	@Value("${shiro.unauthc.url}")
	private String unauthorizedUrl;

	@Value("${shiro.success.url}")
	private String successUrl;
	
	@Value("${shiro.session.timeout}")
	private int sessionTimeOut;

	@Bean
	public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
		ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
		shiroFilterFactoryBean.setSecurityManager(securityManager);// 必须设置 SecurityManager
		ShiroFilterFactoryBean filter = new ShiroFilterFactoryBean();
        filter.setSecurityManager(securityManager());
        filter.setUnauthorizedUrl("");
        filter.setLoginUrl("/login");
        filter.setSuccessUrl(successUrl);
		return shiroFilterFactoryBean;
	}
	
	//org.apache.shiro.authz.UnauthorizedException

//    @Bean
//    public HashedCredentialsMatcher hashedCredentialsMatcher() {
//        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
//        hashedCredentialsMatcher.setHashAlgorithmName(ALGORITHM_NAME); // 散列算法
//        hashedCredentialsMatcher.setHashIterations(HASH_ITERATIONS); // 散列次数
//        return hashedCredentialsMatcher;
//    }

	@Bean
	public ShiroRealm shiroRealm() {
		ShiroRealm shiroRealm = new ShiroRealm();
		// shiroRealm.setCredentialsMatcher(hashedCredentialsMatcher()); // 原来在这里
		shiroRealm.setCachingEnabled(true);
		// 启用身份验证缓存，即缓存AuthenticationInfo信息，默认false
		shiroRealm.setAuthenticationCachingEnabled(false);
		// 缓存AuthenticationInfo信息的缓存名称 在ehcache-shiro.xml中有对应缓存的配置
		//shiroRealm.setAuthenticationCacheName("authenticationCache");
		// 启用授权缓存，即缓存AuthorizationInfo信息，默认false
		//shiroRealm.setAuthorizationCachingEnabled(false);
		// 缓存AuthorizationInfo信息的缓存名称 在ehcache-shiro.xml中有对应缓存的配置
		//shiroRealm.setAuthorizationCacheName("authorizationCache");
		return shiroRealm;
	}

	/**
	 * 配置 SecurityManager
	 * @return
	 */
	@Bean
	public SecurityManager securityManager() {
		DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
		securityManager.setRealm(shiroRealm());
		//securityManager.setCacheManager(ehCacheManager());
        securityManager.setSessionManager(sessionManager());
		return securityManager;
	}

	/**
	 * 配置session监听
	 * @return
	 */
	@Bean
	public ShiroSessionListener sessionListener() {
		ShiroSessionListener sessionListener = new ShiroSessionListener();
		return sessionListener;
	}

	/**
	 * 配置会话ID生成器
	 * 
	 * @return
	 */
	@Bean
	public SessionIdGenerator sessionIdGenerator() {
		return new JavaUuidSessionIdGenerator();
	}

	/**
	 * 配置保存sessionId的cookie 注意：这里的cookie 不是上面的记住我 cookie 记住我需要一个cookie session管理
	 * 也需要自己的cookie
	 * @return
	 */
	@Bean
	public SimpleCookie sessionIdCookie() {
		// 这个参数是cookie的名称
		SimpleCookie simpleCookie = new SimpleCookie("sid");
		// setcookie的httponly属性如果设为true的话，会增加对xss防护的安全系数。它有以下特点：
		// setcookie()的第七个参数
		// 设为true后，只能通过http访问，javascript无法访问
		// 防止xss读取cookie
		simpleCookie.setHttpOnly(true);
		simpleCookie.setPath("/");
		// maxAge=-1表示浏览器关闭时失效此Cookie <!-- 记住我cookie生效时间30天 ,单位秒;-->
		simpleCookie.setMaxAge(-1);
		return simpleCookie;
	}
	
	/**
	 * shiro缓存管理器; 需要添加到securityManager中
	 * @return
	 */
//	  @Bean public EhCacheManager ehCacheManager() { 
//		  EhCacheManager cacheManager = new EhCacheManager();
//		  cacheManager.setCacheManagerConfigFile("classpath:ehcache/ehcache-shiro.xml"); 
//		  return cacheManager; 
//	  }

	/**
	 * 配置会话管理器，设定会话超时及保存
	 * @return
	 */
	@Bean
	public SessionManager sessionManager() {
		ShiroSessionManager sessionManager = new ShiroSessionManager();
		Collection<SessionListener> listeners = new ArrayList<SessionListener>();
		// 配置监听
		listeners.add(sessionListener());
		sessionManager.setSessionListeners(listeners);
		//sessionManager.setSessionIdCookie(sessionIdCookie());
		// sessionManager.setSessionDAO(sessionDAO());
//		sessionManager.setCacheManager(ehCacheManager());
		// 全局会话超时时间（单位毫秒），默认30分钟 暂时设置为10秒钟 用来测试
		System.out.println();
		if(sessionTimeOut!=0) {
			sessionManager.setGlobalSessionTimeout(1000*60*sessionTimeOut);
		}else {
			System.out.println("默认设置会话="+(1000*60*30));
			sessionManager.setGlobalSessionTimeout(1000*60*30);
		}
		
		// 是否开启删除无效的session对象 默认为true
		sessionManager.setDeleteInvalidSessions(true);
		// 是否开启定时调度器进行检测过期session 默认为true
		sessionManager.setSessionValidationSchedulerEnabled(true);
		// 设置session失效的扫描时间, 清理用户直接关闭浏览器造成的孤立会话 默认为 1个小时
		// 设置该属性 就不需要设置 ExecutorServiceSessionValidationScheduler
		// 底层也是默认自动调用ExecutorServiceSessionValidationScheduler
		// 暂时设置为 5秒 用来测试
		sessionManager.setSessionValidationInterval(1000*60*30);
		// 取消url 后面的 JSESSIONID
		sessionManager.setSessionIdUrlRewritingEnabled(false);
		return sessionManager;

	}

	/**
	 * 开启shiro aop注解支持. 使用代理方式;所以需要开启代码支持;
	 * @param securityManager
	 * @return
	 */
	@Bean
	public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
		AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
		authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
		return authorizationAttributeSourceAdvisor;
	}
	
   
   /**
    * 自动创建代理，没有这个鉴权可能会出错
    * @return
    */
   @Bean
   public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
       DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
       autoProxyCreator.setProxyTargetClass(true);
       return autoProxyCreator;
   }

}
